// JjcapData.cpp: implementation of the CJjcapData class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "jjcap.h"
#include "JjcapData.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

extern CJjcapData CapData;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CJjcapData::CJjcapData()
{
	hthread = NULL;
	adapter = NULL;
	adapter_info = NULL;
	adapter_list = NULL;
	break_loop = 0;
	cap_cnt = 0;
	start_time.tv_sec = 0;
	start_time.tv_usec = 0;
	use_promisc = true;
	max_pack_cap = 0;
}

CJjcapData::~CJjcapData()
{
	Unload();
}

void CJjcapData::Load()
{
	char errbuf[PCAP_ERRBUF_SIZE];
	
	pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &adapter_list, errbuf);
}

void CJjcapData::Unload()
{
	adapter_info = NULL;
	if (adapter)
	{
		pcap_close(adapter);
		adapter = NULL;
	}
	if (adapter_list)
	{
		pcap_freealldevs(adapter_list);
		adapter_list = NULL;
	}
	DeleteAllData();
}

const cap_data* CJjcapData::AppendData(int index, const pcap_pkthdr *hdr, const u_char *data)
{
	if (!hdr || !data)
	{
		return NULL;
	}
	cap_data temp;
	temp.index = index;
	temp.hdr = *hdr;
	if (temp.buf = new BYTE[hdr->caplen])
	{
		memcpy(temp.buf, data, hdr->caplen);
		cap_list.push_back(temp);
		cap_cnt++;
		pack_stat.total++;
		pack_stat.total_bytes += hdr->caplen;
		end_time.tv_sec = hdr->ts.tv_sec;
		end_time.tv_usec = hdr->ts.tv_usec;
		return &cap_list.back();
	}
	return NULL;
}

void CJjcapData::DeleteAllData()
{
	list<cap_data>::iterator itr;
	for (itr = cap_list.begin(); itr != cap_list.end(); itr++)
	{
		delete itr->buf;
		itr->buf = NULL;
	}
	cap_list.clear();
	cap_cnt = 0;
	pack_stat.Clear();
}

const cap_data* CJjcapData::FindData(int index)
{
	if (index < 0 || index >= cap_cnt)
		return NULL;

	int i = 0;
	for (list<cap_data>::iterator itr = cap_list.begin(); itr != cap_list.end(); itr++, i++)
	{
		if (index == i)
		{
			return &(*itr);
		}
	}
	return NULL;
}

void CJjcapData::InterpretHeader(const pcap_pkthdr* caphdr, pack_hdr *phdr, const u_char *content)
{
	phdr->eth = (ether_header*)(content);
	u_short type = ntohs(phdr->eth->type);
	if (type == 0x0800)
	{
		CapData.pack_stat.ip++;
		CapData.pack_stat.ip_bytes += caphdr->caplen;
		phdr->ip = (ip_header*)(content + 14);
		phdr->proto = phdr->ip->proto;
		
		int ip_len = (phdr->ip->ver_ihl & 0xF) * 4;
		
		phdr->udp = (udp_header*)(content + (14 + ip_len));

		if (phdr->proto == IPPROTO_UDP)
		{
			CapData.pack_stat.udp++;
			CapData.pack_stat.udp_bytes += caphdr->caplen;
			if (ntohs(phdr->udp->dport) == 53 || ntohs(phdr->udp->sport) == 53)
			{
				CapData.pack_stat.dns++;
				CapData.pack_stat.dns_bytes += caphdr->caplen;
				phdr->dns = (dns_header*)((u_char*)(phdr->udp) + 8);
			}
			if (ntohs(phdr->udp->dport) == 8000 || ntohs(phdr->udp->sport) == 8000)
			{
				CapData.pack_stat.oicq++;
				CapData.pack_stat.oicq_bytes += caphdr->caplen;
				phdr->oicq = (oicq_header*)((u_char*)(phdr->udp) + 8);
			}
		}
		else if (phdr->proto == IPPROTO_TCP)
		{
			CapData.pack_stat.tcp++;
			CapData.pack_stat.tcp_bytes += caphdr->caplen;
			if (ntohs(phdr->tcp->dport) == 80 || ntohs(phdr->tcp->sport) == 80)
			{
				CapData.pack_stat.http++;
				CapData.pack_stat.http_bytes += caphdr->caplen;
			}
		}
		else if (phdr->proto == IPPROTO_ICMP)
		{
			CapData.pack_stat.icmp++;
			CapData.pack_stat.icmp_bytes += caphdr->caplen;
		}
		else if (phdr->proto == IPPROTO_IGMP)
		{
			CapData.pack_stat.igmp++;
			CapData.pack_stat.igmp_bytes += caphdr->caplen;
		}
	}
	else if (type == 0x0806)
	{
		CapData.pack_stat.arp++;
		CapData.pack_stat.arp_bytes += caphdr->caplen;

		phdr->ip = NULL;
		phdr->proto = 0;
		phdr->arp = (arp_header*)(content + 14);
	}
}

int CJjcapData::GetDNSRequestDomain(int begin, pack_hdr& h, CString& name)
{
	int i = begin, j;
	name = _T("");
	for (; h.dns->buf[i]; i = j)
	{
		int max_n = i + h.dns->buf[i] + 1;
		for (j = i + 1; j < max_n; j++)
		{
			name += h.dns->buf[j];
		}
		if (h.dns->buf[j])
		{
			name += '.';
		}
	}
	return j+1;
}

int CJjcapData::GetDNSRequestDomainByLength(int begin, pack_hdr& h, CString& name, int len)
{
	int i = begin, j = begin + 1;
	name = _T("");
	for (; j < begin + len; i = j)
	{
		int max_n = i + h.dns->buf[i] + 1;
		for (j = i + 1; j < max_n; j++)
		{
			name += h.dns->buf[j];
		}
		if (j < begin + len && h.dns->buf[j])
		{
			name += '.';
		}
	}
	return begin + len;
}

int CJjcapData::GetDNSRequestDomainClass(int begin, pack_hdr& h, CString& type, CString& clas)
{
	u_short _type = ntohs(*((u_short*)(&h.dns->buf[begin])));
	switch (_type)
	{
	case 1:
		type = _T("A");
		break;
	case 2:
		type = _T("NS");
		break;
	case 5:
		type = _T("CNAME");
		break;
	case 6:
		type = _T("SOA");
		break;
	case 11:
		type = _T("WKS");
		break;
	case 12:
		type = _T("PTR");
		break;
	case 13:
		type = _T("HINFO");
		break;
	case 15:
		type = _T("MX");
		break;
	case 28:
		type = _T("AAAA");
		break;
	case 252:
		type = _T("AXFR");
		break;
	case 255:
		type = _T("ANY");
		break;
	}
	u_short cls = ntohs(*((u_short*)(&h.dns->buf[begin+2])));
	if (cls == 1)
	{
		clas = _T("IN");
	}
	return begin+4;
}

void CJjcapData::GetOICQCmdName(u_short cmd, CString& name)
{
	switch (cmd)
	{
	case OICQ_FLAG_GETFRIENDSTAT:
		name = _T("Get status of friend");
		break;
	case OICQ_FLAG_GROUPOPS:
		name = _T("Group operation");
		break;
	case OICQ_FLAG_REQUESTKEY:
		name = _T("Request key");
		break;
	case OICQ_FLAG_HEARTBEAT:
		name = _T("Heart message");
		break;
	case OICQ_FLAG_LOGOUT:
		name = _T("Log out");
		break;
	case OICQ_FLAG_GETFRIENDONLINE:
		name = _T("Get friend online");
		break;
	case OICQ_FLAG_GETLEVEL:
		name = _T("Get level");
		break;
	case OICQ_FLAG_GROUPNAMEOPS:
		name = _T("Group name operation");
		break;
	case OICQ_FLAG_REQUESTEXTRAINFO:
		name = _T("Request extra information");
		break;
	case OICQ_FLAG_RECVMESSAGE:
		name = _T("MEMO operation");
		break;
	case OICQ_FLAG_MEMOOPS:
		name = _T("Receive message");
		break;
	case OICQ_FLAG_REQUESTLOGIN:
		name = _T("Request login");
		break;
	case OICQ_FLAG_DLGROUPFRIEND:
		name = _T("Download group friend");
		break;
	case OICQ_FLAG_GETGROUPSTAT:
		name = _T("Get friend's status of group");
		break;
	}
}